/**
	License:		Artistic license 2.0 (see license.txt, also available online at http://www.perlfoundation.org/artistic_license_2_0)
	Authors:		OrbitalLab (http://www.orbitallab.ru/moonglide/), 2007-2009

	File:			demoscene.d
	Description:	custom scene with massive testing
	Date:			28.03.2008 by Digited
**/
module client.customscenes.demoscene.DemoScene;

import
	MoonGlide,

	client.customscenes.demoscene.AnimPlanet,

	moonglide.gui.GuiTextureCache,
	moonglide.renderer.opengl.OpenGLShaderWork,
	moonglide.resources.resproc.mesh.ResPMesh,
	moonglide.resources.resproc.texture.ResPTex;

static this()
{
	CSceneManager().addScene( new CParTestScene );
	CSceneManager().addScene( new CDemoScene );
}

class CParTestScene : IScene
{
	mixin TEventGenerator;

	protected:
		bool				_initialized,
							_shutdowndone;

		CFreeMoveAnimator	_freeCameraAnimator;

		CSceneLayer[]		_layers;
		CEngCamera[]		_cameras;

		CConfig				_cfg;
		char[]				_cfgFileName;

	public:
		bool 				initialized()	{ return _initialized;}

		CSceneLayer[]		layers()		{ return _layers; }
		CEngCamera[]		cameras()		{ return _cameras; }

        CEngParSystem addParticleSystem1()
        {
			auto par = new CEngParSystem( "demo_parsys" );
			par.xxTexture = _cfg.getString( "res_particle_1" );
			par.floats["maxsize"]	= 2.0f;
			par.floats["minsize"]	= 1.0f;
			par.floats["spread"]	= 0.0f;
			par.floats["posspread"]	= 0.0f;

			par.floats["changeR"]	= 0.001f;
			par.floats["changeG"]	= -0.001f;
			par.floats["changeB"]	= 0.001f;
			par.floats["changeA"]	= 0.001f;
			par.floats["rate"]		= 0.02f;
			par.bools["lifedown"]	= true;
			par.floats["lifetime"]  = 50.0f;
			par.ints["maxpar"]		= 100;
			par.floats["maxspeed"]	= 0.25f;
			par.floats["minspeed"]	= 0.25f;

			par.material.bools["Blend"] = true;
			par.material.bools["AlphaTest"] = false;
			par.material.ints["DepthMask"] = 0;

			par.setCamera( _cameras[0] );
			par.rendType =  eparsysrendertype.ffp_line;
			par.aligned =  eparsystalign.to_Camera;
			par.sort_Life = true;
            par.sort_FarToNear = false;

			auto parAnim = new CSimplParAnimator( par );
			par.animators[ parAnim.id ] = parAnim;

            return par;
        }

        CEngParSystem addAlphaParticleSystem()
        {
			auto par = new CEngParSystem( "demo_alpha_parsys" );
			par.xxTexture = _cfg.getString( "res_alpha_particle" );
			par.floats["maxsize"]	= 4.0f;
			par.floats["minsize"]	= 2.0f;
			par.floats["spread"]	= 1.0f;
			par.floats["posspread"]	= 0.0f;

			par.floats["changeR"]	= 0.001f;
			par.floats["changeG"]	= 0.001f;
			par.floats["changeB"]	= 0.001f;
			par.floats["changeA"]	= -0.001f;
			par.floats["rate"]		= 0.055f;
			par.bools["lifedown"]	= true;
			par.floats["lifetime"]  = 10.0f;
			par.ints["maxpar"]		= 50;
			par.floats["maxspeed"]	= 0.005f;
			par.floats["minspeed"]	= 0.001f;

			par.setCamera( _cameras[0] );
			par.rendType =  eparsysrendertype.sprites_rot;
			par.aligned =  eparsystalign.to_Camera;
			par.sort_Life = false;
            par.sort_FarToNear = true;
            par.vector.set(0,1,0);

            par.material.bools["Blend"] = true;
            par.material.ints["DepthMask"] = par.material.bools["Blend"] ? 0 : 1;

			par.material.bools["AlphaTest"] = true;
			par.material.bools["OnlyHDR"] = false;

		//	par.material.sourceBlendFactor		= EMatBlendSFactor.one;
		//	par.material.destBlendFactor		= EMatBlendDFactor.one;

			auto parAnim = new CSimplParAnimator( par );
			par.animators[ parAnim.id ] = parAnim;

            return par;
        }

        CEngGeometry addSphere()
        {
            auto Sph = new CEngGeometry( "sphere" );
			Sph.position.set( 1, 1, 0 );

            Sph.addLod( genMeshSphere( 1, 3 ), 0 );

            Sph.material.shader.setProg( sh_Vertex , CResShader( _cfg.getString( "res_phong_vertex_sh" ), true ));
			Sph.material.shader.setProg( sh_Fragment, CResShader( _cfg.getString( "res_phong_tex_sh" ), true ));

			return Sph;
        }


        CEngGeometry addShip()
        {
            auto COR = new CEngGeometry( "cor1" );
			COR.position.set( 10.0, -30, 0 );

			COR.addLod( CResMesh( _cfg.getString( "res_ship_lod0" ), true ), 0 );
		//	COR.addLod( CResMesh( _cfg.getString( "res_ship_lod0" ), true ), 100);
			//COR.addLod( CResMesh( _cfg.getString( "res_ship_lod0" ), true ), 200);

			COR.material.ints["shininess"] = 60;

			COR.material.newTexture( _cfg.getString( "res_ship_diftex" ), true );
			COR.material.newTexture( _cfg.getString( "res_ship_normals_tex" ), true );

			COR.material.newTexture().data =
			[
				CResTextureData( _cfg.getString( "res_skybox_bk" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_dn" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_ft" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_lf" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_rt" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_up" ), true )
			];

			CResTexture tmptex = COR.material.textures[$-1];
			tmptex.data[0].texType = ETexTarget.Tex_Cube_Z_Neg;
			tmptex.data[1].texType = ETexTarget.Tex_Cube_Y_Neg;
			tmptex.data[2].texType = ETexTarget.Tex_Cube_Z_Pos;
			tmptex.data[3].texType = ETexTarget.Tex_Cube_X_Pos;
			tmptex.data[4].texType = ETexTarget.Tex_Cube_X_Neg;
			tmptex.data[5].texType = ETexTarget.Tex_Cube_Y_Pos;
			tmptex.textureType = Tex_Cube;

			COR.material.newTexture( _cfg.getString( "res_ship_specular" ), true );
			COR.material.newTexture( _cfg.getString( "res_ship_height" ), true );

            COR.material.shader.setProg( sh_Vertex , CResShader( _cfg.getString( "res_bump_vertex_sh" ), true ));
			COR.material.shader.setProg( sh_Fragment, CResShader( _cfg.getString( "res_bump_tex_sh" ), true ));
			COR.material.shader.addLocal( "colorMap", 0 , true);
			COR.material.shader.addLocal( "normalMap", 1 , true);
			//COR.material.shader.addLocal( "envCubeMap", 2 , true);
			COR.material.shader.addLocal( "glossMap", 3 , true);
			COR.material.shader.addLocal( "heightMap", 4 , true);

			COR.material.shader.progs[ sh_Fragment ].setDefine("USE_GLOSS");
			COR.material.shader.progs[ sh_Fragment ].setDefine("USE_PARALLAX");
			//COR.material.shader.progs[ sh_Fragment ].setDefine("USE_ENV");
			//COR.material.shader.progs[ sh_Fragment ].setDefine("USE_ENV_FRESNEL");

			auto spr3 = new CEngSprite( "sprite" );

			spr3.position.set( 0,0,-3.1 );
			spr3.mat.newTexture( _cfg.getString( "res_sprite_3" ), true );
			spr3.size = Vector3f( 200.f,200.f,1.f );

            spr3.floats["alphadelta"] = 0.01f;
			spr3.floats["rotSpeed"] = 1.0f;
			spr3.bools["ScreenAligned"]	=true;
			spr3.bools["ZVisiTest"]	=true;
            spr3.bools["rot"]	=true;

			with( spr3.mat )
			{
				bools["Blend"]		= true;
				bools["Lighting"]	= false;
				bools["DepthTest"]	= false;
			}

			COR.addChild(spr3);

			auto a = addParticleSystem1();
			a.position.set(0,0,-3);
			COR.addChild( a );
			a.vector.set(0,0,-0.0001);

			a.floats["maxsize"]	= 1.0f;
			a.floats["minsize"]	= 1.0f;

			a.floats["changeR"]		= 0.001f;
			a.floats["changeG"]		= 0.001f;
			a.floats["changeB"]		= 0.001f;
			a.floats["changeA"]		= 0.001f;
			a.floats["rate"]		= 0.02f;
			a.bools["lifedown"]		= true;
			a.floats["lifetime"]	= 100.0f;
			a.ints["maxpar"]		= 1000;
			a.floats["maxspeed"]	= 0.01f;
			a.floats["minspeed"]	= 0.01f;

            return COR;
        }

        CEngParSystem addDust()
        {
			auto pardust = new CEngParSystem( "anotherParSys" );
			pardust.position.set( 0,0,0 );
			pardust.xxTexture = _cfg.getString( "res_particle" );
			pardust.floats["maxsize"]	= 0.1f;
			pardust.floats["minsize"]	= 0.05f;
			pardust.floats["spread"]	= 0.0f;
			pardust.floats["posspread"]	= 100.0f;

			pardust.floats["rate"]		= 1000f;
			pardust.bools["lifedown"]	= false;
			pardust.ints["maxpar"]		= 1000;
			pardust.floats["maxspeed"]	= 0.0001f;
			pardust.floats["minspeed"]	= 0.0001f;

			pardust.bools["killdist"]	= true;
			pardust.floats["killdist"]  = 100.0f;

			pardust.material.bools["Blend"] = true;
			pardust.material.bools["AlphaTest"] = false;
			pardust.material.ints["DepthMask"] = 0;

			pardust.vector.set(0,0,0);
			pardust.setCamera( _cameras[0] );
			pardust.rendType =  eparsysrendertype.sprites_rot;
			pardust.aligned =  eparsystalign.to_Camera;
			pardust.sort_Life = false;

			auto parAnim22 = new CSimplParAnimator( pardust );
			pardust.animators[ parAnim22.id ] = parAnim22;
			return pardust;
        }

        CEngGeometry addSky()
        {
            auto sky = new CEngGeometry( "skybox" );
			sky.lodDistance		= -1;
			sky.rendPriority	= 20;
			//sky.orientation		= Matrix33f.rotationY(PI);

			sky.addLod( genMeshSphere( 10,2 ), 0 );

			sky.material.bools["BackCull"]    		= false;
            sky.material.bools["Lighting"]     		= false;
			sky.material.bools["DepthRanged"]		= true;
            sky.material.floats["DepthRangeNear"]	= 0.999f;

            with( sky.material )
            {
                vectors4["color"]		= Vector4f(1.0f,1.0f,1.0f,1.0f);
                vectors4["ambient"]		= Vector4f(1.0f,1.0f,1.0f,1.0f);
                vectors4["diffuse"]		= Vector4f(1.0f,1.0f,1.0f,1.0f);
                vectors4["specular"]	= Vector4f(0.0f,0.0f,0.0f,1.0f);
                vectors4["emission"]	= Vector4f(1.0f,1.0f,1.0f,1.0f);
            }

			sky.material.newTexture().data =
			[
				CResTextureData( _cfg.getString( "res_skybox_bk" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_dn" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_ft" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_lf" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_rt" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_up" ), true )
			];

			CResTexture tmptex = sky.material.textures[$-1];

			tmptex.data[0].texType = ETexTarget.Tex_Cube_Z_Neg;
			tmptex.data[1].texType = ETexTarget.Tex_Cube_Y_Neg;
			tmptex.data[2].texType = ETexTarget.Tex_Cube_Z_Pos;
			tmptex.data[3].texType = ETexTarget.Tex_Cube_X_Pos;
			tmptex.data[4].texType = ETexTarget.Tex_Cube_X_Neg;
			tmptex.data[5].texType = ETexTarget.Tex_Cube_Y_Pos;

			tmptex.textureType = Tex_Cube;
			tmptex.swapCube = true;
            return sky;
        }

        CEngGeometry addPlanetSys()
        {
/// SUN
///////////
			auto light = new CEngLight( "someLight" );
			with( light )
			{
                Ambient		=	Vector4f( 0.3, 0.3, 0.3, 1.0 ),
                Diffuse		=	Vector4f( 0.7, 0.7, 0.7, 1.0 ),
                Specular	=	Vector4f( 1.0, 1.0, 1.0, 1.0 );
			}

            auto SUN = new CEngGeometry( "sun" );
            SUN.addChild( light );

			SUN.position.set( 0.0, 0, 10 );
			SUN.addLod( genMeshSphere( 100, 5 ), 0 );
			SUN.addLod( genMeshSphere( 100, 2 ), 1000 );
			SUN.addLod( genMeshEmpty( ), 2500 );

/// SUN . material
			SUN.material.vectors4["emission"] = Vector4f( 1.f, 1.f, 1.f );
			SUN.material.bools["OnlyHDR"] = false;
			SUN.material.newTexture( _cfg.getString( "res_sun_mat_tex" ), true );
//////////
			auto SUN_AN = new CAnimPlanet(SUN);
			SUN.animators[ SUN_AN.id ] = SUN_AN;

			SUN_AN.parRot = 0.0f;
			SUN_AN.selfRot = 0.0;
/// PLANET
///////////
			auto EARTH = new CEngGeometry( "earth" );
			EARTH.addLod( genMeshSphere( 60, 3 ), 0 );
			EARTH.addLod( genMeshSphere( 60, 3 ), 1000 );
			EARTH.addLod( genMeshSphere( 60, 1 ), 3000 );

/*
			auto EARTHatm = new CEngGeometry( "earthAtm" );
			EARTHatm.addLod( genMeshSphere( 65, 3 ), 0 );
			EARTHatm.addLod( genMeshSphere( 65, 2 ), 1000 );
			EARTHatm.addLod( genMeshSphere( 65, 1 ), 3000 );

			with( EARTHatm.material )
			{
                ints["shininess"] = 1;
			    vectors4["color"]		= Vector4f(0.0f,0.0f,0.0f,0.0);
                vectors4["ambient"]		= Vector4f(0.0f,0.0f,0.0f,0.4f);
                vectors4["diffuse"]		= Vector4f(0.0f,0.0f,0.0f,0.0f);
                vectors4["specular"]	= Vector4f(0.3f,0.3f,0.3f,0.3f);
                vectors4["emission"]	= Vector4f(0.0f,0.0f,0.0f,0.0f);
                bools["Blend"] = true;
                bools["OnlyHDR"] = true;
                sourceBlendFactor	= EMatBlendSFactor.one;
				destBlendFactor		= EMatBlendDFactor.one;
			}

            EARTH.addChild( EARTHatm );
*/
			EARTH.position.set( 800.0, 0, 0 );

/// PLANET . material
			with( EARTH.material )
			{
                ints["shininess"]		= 10;
                vectors4["color"]		= Vector4f(0.7f,0.7f,0.7f,1);
                vectors4["ambient"]		= Vector4f(0.5f,0.5f,0.5f,1);
                vectors4["diffuse"]		= Vector4f(0.2f,0.2f,0.2f,1);
                vectors4["specular"]	= Vector4f(1.0f,1.0f,1.0f,1);
                vectors4["emission"]	= Vector4f(0.0f,0.0f,0.0f,1);
			}

			EARTH.material.newTexture( _cfg.getString( "res_earthmap_tex" ), true );
			EARTH.material.newTexture( _cfg.getString( "res_earth_mat_tex" ), true );
/*
			EARTH.material.newTexture().data =
			[
				CResTextureData( _cfg.getString( "res_skybox_bk" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_dn" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_ft" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_lf" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_rt" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_up" ), true )
			];

			CResTextureData tmptex = null;
			tmptex = EARTH.material.textures[$-1];
			tmptex.data[0].texType = ETexTarget.Tex_Cube_Z_Neg;
			tmptex.data[1].texType = ETexTarget.Tex_Cube_Y_Neg;
			tmptex.data[2].texType = ETexTarget.Tex_Cube_Z_Pos;
			tmptex.data[3].texType = ETexTarget.Tex_Cube_X_Pos;
			tmptex.data[4].texType = ETexTarget.Tex_Cube_X_Neg;
			tmptex.data[5].texType = ETexTarget.Tex_Cube_Y_Pos;
			tmptex.textureType = Tex_Cube;
*/
			EARTH.material.newTexture( _cfg.getString( "res_earth_mat_tex1" ), true );
			EARTH.material.newTexture( _cfg.getString( "res_earthlight_tga" ), true );
//			EARTH.material.newTexture().data ~= GenTexFill;//CResTextureData( "data/113.jpg", true ); // NOTE: if use this, place 113.jpg in config

			EARTH.material.shader.setProg( sh_Vertex , CResShader( _cfg.getString( "res_earth_vertex_sh" ), true ));
			EARTH.material.shader.setProg( sh_Fragment, CResShader( _cfg.getString( "res_earth_tex_sh" ), true ));
			EARTH.material.shader.addLocal( "colorMap", 0 , true);
			EARTH.material.shader.addLocal( "normalMap", 1 , true);
			EARTH.material.shader.addLocal( "glossMap", 2 , true);
			EARTH.material.shader.addLocal( "nightMap", 3 , true);

			float invRa = ( light.radius == 0.0f ) ? 0.0f : 1.0f / light.radius;

			EARTH.material.shader.addLocal( "invRadius", invRa , true);

			EARTH.material.shader.progs[ sh_Fragment ].setDefine("USE_GLOSS");
			EARTH.material.shader.progs[ sh_Fragment ].setDefine("USE_PARALLAX");
			//EARTH.material.shader.progs[ sh_Fragment ].setDefine("USE_ENV");
			//EARTH.material.shader.progs[ sh_Fragment ].setDefine("USE_ENV_FRESNEL");

///////////

			CAnimPlanet EAR_AN = new CAnimPlanet(EARTH);
			EARTH.animators[ EAR_AN.id ] = EAR_AN;

			EAR_AN.parRot = 0.0001;
			EAR_AN.selfRot = 0.05;

			SUN.addChild( EARTH );

			Cout( "3" ).newline;

		//	SUN.floats["endVis"]  = 450.0f;
			return SUN;
        }

        void addSunSprite()
        {
            Vector3f pos = Vector3f (100.f, 100.f, 100.f);
			auto spr = new CEngSprite( "sprite" );

			spr.position = pos;
			spr.mat.newTexture( _cfg.getString( "res_sprite_3" ), true );
			spr.size = Vector3f( 300.f,300.f,1.f );

            spr.floats["alphadelta"] = 0.005f;
			spr.floats["rotSpeed"] = 2.0f;
			spr.bools["ScreenAligned"]	=true;
			spr.bools["ZVisiTest"]	=true;
            spr.bools["rot"]	=true;

			with( spr.mat )
			{
				bools["Blend"]		= true;
				bools["Lighting"]	= false;
				bools["DepthTest"]	= false;
			}

			layers[0].addChild(spr);

			auto spr2 = new CEngSprite( "sprite" );

			spr2.position =  pos;
			spr2.mat.newTexture( _cfg.getString( "res_sprite_3_tga" ), true );
			spr2.size = Vector3f( 1200.f,80.f,1.f );

            spr2.floats["alphadelta"] = 0.01f;
			spr2.bools["ScreenAligned"]	=true;
			spr2.bools["ZVisiTest"]	=true;
            spr2.bools["rot"]	=false;

			with( spr2.mat )
			{
				bools["Blend"]		= true;
				bools["Lighting"]	= false;
				bools["DepthTest"]	= false;
			}

			layers[0].addChild(spr2);

			auto spr3 = new CEngSprite( "sprite" );

			spr3.position = pos;
			spr3.mat.newTexture( _cfg.getString( "res_sprite_1" ), true );
			spr3.size = Vector3f( 400.f,400.f,1.f );

            spr3.floats["alphadelta"]	= 0.01f;
			spr3.floats["rotSpeed"]		= 1.0f;
			spr3.bools["ScreenAligned"]	= false;
			spr3.bools["ZVisiTest"]		= false;
            spr3.bools["rot"]			= true;

			with( spr3.mat )
			{
				bools["Blend"]		= true;
				bools["Lighting"]	= false;
				bools["DepthTest"]	= true;
			}

			layers[0].addChild(spr3);
        }


        void addMoon()
        {
            auto moon = new CEngGeometry( "moon" );
            moon.addLod( genMeshSphere( 20, 3 ), 0 );
			moon.addLod( genMeshSphere( 20, 2 ), 1000 );
			moon.addLod( genMeshSphere( 20, 1 ), 2000 );

			moon.position.set( 300.0, 0, 0 );

/// MOON . material
			with( moon.material )
			{
                ints["shininess"] = 10;
                vectors4["color"]		= Vector4f(0.7f,0.7f,0.7f,1);
                vectors4["ambient"]		= Vector4f(0.5f,0.5f,0.5f,1);
                vectors4["diffuse"]		= Vector4f(0.2f,0.2f,0.2f,1);
                vectors4["specular"]	= Vector4f(1.0f,1.0f,1.0f,1);
                vectors4["emission"]	= Vector4f(0.0f,0.0f,0.0f,1);
			}


			moon.material.newTexture().data ~= CResTextureData( _cfg.getString( "res_earthmap_tex" ), true );
			moon.material.newTexture().data ~= CResTextureData( _cfg.getString( "res_earth_mat_tex" ), true );
/*
			moon.material.newTexture().data =
			[
				CResTextureData( "data/sky/"~aaa~"_bk."~aaaext, true ),
				CResTextureData( "data/sky/"~aaa~"_dn."~aaaext, true ),
				CResTextureData( "data/sky/"~aaa~"_ft."~aaaext, true ),
				CResTextureData( "data/sky/"~aaa~"_lf."~aaaext, true ),
				CResTextureData( "data/sky/"~aaa~"_rt."~aaaext, true ),
				CResTextureData( "data/sky/"~aaa~"_up."~aaaext, true )
			];

			CResTexture tmptex = null;
			tmptex = moon.material.textures[$-1];
			tmptex.data[0].texType = ETexTarget.Tex_Cube_Z_Neg;
			tmptex.data[1].texType = ETexTarget.Tex_Cube_Y_Neg;
			tmptex.data[2].texType = ETexTarget.Tex_Cube_Z_Pos;
			tmptex.data[3].texType = ETexTarget.Tex_Cube_X_Pos;
			tmptex.data[4].texType = ETexTarget.Tex_Cube_X_Neg;
			tmptex.data[5].texType = ETexTarget.Tex_Cube_Y_Pos;
			tmptex.textureType = Tex_Cube;
*/
			moon.material.newTexture().data ~= CResTextureData( _cfg.getString( "res_earth_mat_tex1" ), true );

//			moon.material.newTexture().data ~= GenTexFill;//CResTextureData( "data/113.jpg", true );

			moon.material.shader.setProg( sh_Vertex , CResShader( _cfg.getString( "res_bump_vertex_sh" ), true ));
			moon.material.shader.setProg( sh_Fragment, CResShader( _cfg.getString( "res_bump_tex_sh" ), true ));
			moon.material.shader.addLocal( "colorMap", 0 , true);
			moon.material.shader.addLocal( "normalMap", 1 , true);
			moon.material.shader.addLocal( "glossMap", 2 , true);

			float invRa = 0.f;

			moon.material.shader.addLocal( "invRadius", invRa , true);

			moon.material.shader.progs[ sh_Fragment ].setDefine("USE_GLOSS");
			//moon.material.shader.progs[ sh_Fragment ].setDefine("USE_PARALLAX");
			//EARTH.material.shader.progs[ sh_Fragment ].setDefine("USE_ENV");
			//EARTH.material.shader.progs[ sh_Fragment ].setDefine("USE_ENV_FRESNEL");

            layers[0].addChild(moon);
        }

		bool initialize()
		{
			if( _initialized )
				return false;

			debug debugLogB( "Demo scene initialization started" );

			_cameras ~= new CEngCamera( CEngineCore().renderer.viewport );
			_layers	 ~= new CSceneLayer( "texProcLayer", _cameras[0], CResMaterial( "texProcLayerMaterial" ));

			debug debugLog.trace( "Demo scene: camera & layer are created" );


            auto a = addParticleSystem1;
            auto a1 = addParticleSystem1;
            auto a2 = addParticleSystem1;
            auto b = addParticleSystem1;
            auto c = addParticleSystem1;
            auto d = addParticleSystem1;
            auto e = addParticleSystem1;
            auto f = addParticleSystem1;

            b.material.bools["term"] = true;


            auto light = new CEngLight( "someLight" );
			light.position.set( -10, 10, -10 );
            with( light )
			{
                Ambient		=	Vector4f( 0.7, 0.1, 0.1, 1.0 ),
                Diffuse		=	Vector4f( 0.1, 0.1, 0.1, 1.0 ),
                Specular	=	Vector4f( 0.7, 1.3, 0.3, 1.0 );
			}

            auto light2 = new CEngLight( "someLight2" );
			light2.position.set( 10, -10, 10 );
            with( light2 )
			{
                Ambient		=	Vector4f( 0.1, 0.1, 0.7, 1.0 ),
                Diffuse		=	Vector4f( 0.1, 0.1, 0.1, 1.0 ),
                Specular	=	Vector4f( 0.3, 0.3, 0.7, 1.0 );
			}

            auto light3 = new CEngLight( "someLight3" );
			light3.position.set( -10, -10, 10 );
            with( light3 )
			{
                Ambient		=	Vector4f( 0.1, 0.7, 0.1, 1.0 ),
                Diffuse		=	Vector4f( 0.1, 0.1, 0.1, 1.0 ),
                Specular	=	Vector4f( 0.3, 0.7, 0.3, 1.0 );
			}

             _layers[0].addChild( light3 );
		     _layers[0].addChild( light2 );
             _layers[0].addChild( light );


            auto cub = new CEngGeometry( "cub1" );
			cub.position.set( 100.0, 300, 10 );
			cub.addLod( genMeshCubeNor( Vector3f(10,10,10 )), 0 );
			a.position.set(10,0,0);     a.vector.set(1,0,0);
			a1.position.set(10,4,0);     a1.vector.set(1,0,0);
			a2.position.set(10,-4,0);     a2.vector.set(1,0,0);
			b.position.set(-10,0,0);    b.vector.set(-1,0,0);
			c.position.set(0,10,0);     c.vector.set(0,1,0);
			d.position.set(0,-10,0);    d.vector.set(0,-1,0);
			e.position.set(0,0,10);     e.vector.set(0,0,1);
			f.position.set(0,0,-10);    f.vector.set(0,0,-1);

			_layers[0].addChild( cub );
			cub.addChild( a );
			cub.addChild( a1 );
			cub.addChild( a2 );
			cub.addChild( b );
			cub.addChild( c );
			cub.addChild( d );
			cub.addChild( e );
			cub.addChild( f );

            auto animXlod = new CRotAnim( cub ,0.42,0.71,0.3 );
            cub.animators[ animXlod.id ] = animXlod;
/*
            auto land = new CEngGeometry( "land1" );
            land.material.bools["BackCull"]    		= false;
            _layers[0].addChild( land );

            auto animlod = new CLodAnim( land, CResTextureData( _cfg.getString( "res_land_1_tex" ), true ), _cameras[0] );
            land.animators[ animlod.id ] = animlod;
*/
/// --------------------
            auto term = new CEngGeometry( "term0" );
            term.addLod( genMeshSphere( 50, 1 ), 0 );

            term.position.set( 100.0, 300, 10 );

			with( term.material )
			{
			    bools["term"] = true;
                ints["shininess"] = 10;
                vectors4["color"]		= Vector4f(0.2f,0.2f,0.2f,1);
                vectors4["ambient"]		= Vector4f(0.5f,0.5f,0.5f,1);
                vectors4["diffuse"]		= Vector4f(0.0f,0.0f,0.0f,1);
                vectors4["specular"]	= Vector4f(0.0f,0.0f,0.0f,1);
                vectors4["emission"]	= Vector4f(0.0f,0.0f,0.0f,1);
			}

/// decomment to blow!!!! )
///			auto animXX = new CScaleAnim( term ,1.5,1.5,1.5 );
///         term.animators[ animXX.id ] = animXX;
            _layers[0].addChild( term );
/// --------------------

            auto ship = addShip;
            ship.position.set( 0, 0, 0 );
            auto confFile = CMoonFile.drivers["program"].file( "camera.cfg" );
			auto freeMoveAnimatorConfig = new CConfig;

			if( confFile.exists )
			{
				auto stream = confFile.input;
				freeMoveAnimatorConfig.load( stream );
			}

			_freeCameraAnimator = new CFreeMoveAnimator( ship, SFMASettings( freeMoveAnimatorConfig ));
			ship.animators[ "freemoveAnimator" ] = _freeCameraAnimator;
			_freeCameraAnimator.registerListener( CEngineCore(), eeventtype.program );
//			auto anim = new CAnimShip( ship );
//			ship.animators[ anim.id ] = anim;

//			_cameras[0].position.set(0,0,30);
			_cameras[0].position.set(0,2,-13);
			auto camanim = new CCameraSpec (_cameras[0], ship);
			_cameras[0].animators[ camanim.id ] = camanim;

			//_cameras[0].addChild (ship);

			_layers[0].addChild( ship );
			_cameras[0].addChild( addSky );
			_cameras[0].addChild( addDust );
			addMoon;

//			_layers[0].addChild( addPlanetSys );

//            auto rot = new CRotAnim( cub , 1.5, 1.1,1.0 );
//			cub.animators[ rot.id ] = rot;
	//		auto mov = new CMoveAnim( cub , 10.05, 10.1,0.2 );
		//	cub.animators[ mov.id ] = mov;

            auto cub2 = new CEngGeometry( "cub2" );
			cub2.position.set( 0, 0, -150 );
			cub2.addLod( genMeshCubeNor( Vector3f(12,20,10 )), 0 );
			_layers[0].addChild( cub2 );

			//addSunSprite;

			//IRenderTarget rendTarget = new IRenderTarget;
			//rendTarget.
			//_layers[0].setRenderTarget( rendTarget );

        //    _layers[1].addChild( cub2 );
		//	_layers[1].setRenderTarget( null );

			_initialized = true;

			debug CEngineCore().DbgReport;
			return true;
		}

		//================================================================
		/// process once
		//================================================================
		void run( float frametime )
		{
			// all processing stuff for objects in scene tree using frametime, including moves by accels from onEventCallback;
			foreach( layer; _layers )
				layer.update( frametime, Vector3f.zero, Matrix33f.identity );		// recursive processing

		}

		//================================================================
		/// event callback: all useful input from controllers, system and application comes here between scene runs
		//================================================================
		void onEventCallback( CEvent event, IEventGenerator gen )
		{
			// move camera (and other objects that receive event input,
			//  for example, from GUI elements, that generate gui events)
			passEvent( event, gen );
		}

		void onEventReceive( CEvent event, IEventSender sender )
		{
			//
		}

		//================================================================
		/// shutdown, release & clean stuff
		//================================================================
		void shutdown()
		{
			if( !_initialized || _shutdowndone )
				return;

			debug debugLogB( "particlescene shutdown" );

			foreach( inout lr; _layers )
			{
				if( lr )
					delete lr;
			}

			_layers.length = 0;
			_cameras.length = 0;

			_shutdowndone = true;
			_initialized = false;
		}

		CConfig	getConfig()		{ return _cfg; }

		void	loadConfig()
		{
			if( _cfgFileName.length )
			{
				_cfg = null;
				_cfg = new CConfig( _cfgFileName );
			}
		}

		this( char[] cfgFileName = "partestscene.cfg" )
		{
			_id = "ParDemoScene";
			_cfgFileName = cfgFileName;
		}

		~this() { shutdown(); }

}


//================================================================
/// custom scene with massive testing
//================================================================
class CDemoScene : IScene
{
	mixin TEventGenerator;

	protected:
		bool				_initialized,
							_shutdowndone;

		CFreeMoveAnimator	_freeCameraAnimator;

		CSceneLayer[]		_layers;
		CEngCamera[]		_cameras;

		Vector3f			_zeroVec;
		Matrix33f			_idenMatrix;

        CConfig				_cfg;
        char[]				_cfgFileName;
	public:
		bool 				initialized()	{ return _initialized;}

		//CGUIManager		GUIManager()	{ return _guimanager; }
		CSceneLayer[]		layers()		{ return _layers; }
		CEngCamera[]		cameras()		{ return _cameras; }

		//================================================================
		/// initialization of the scene
		//================================================================
		bool initialize()
		{
			if( _initialized )
				return false;

			debug debugLogB( "Demo scene initialization started" );

			_cameras ~= new CEngCamera( CEngineCore().renderer.viewport );
			_layers	 ~= new CSceneLayer( "rootLayer", _cameras[0], CResMaterial( "rootLayerMaterial" ));

			auto sky = new CEngGeometry( "skybox" );
			sky.lodDistance		= -1;
			sky.rendPriority	= 20;
			//sky.orientation		= Matrix33f.rotationY(PI);

			//sky.addLod( genMeshSphere( 10,2 ), 0 );
			sky.addLod( genMeshCube( Vector3f(10,10,10) ), 0 );

			sky.material.bools["BackCull"]    		= false;
            sky.material.bools["Lighting"]     		= false;
			sky.material.bools["DepthRanged"]		= true;
            sky.material.floats["DepthRangeNear"]	= 0.999f;

			sky.material.newTexture().data =
			[
				CResTextureData( _cfg.getString( "res_skybox_bk" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_dn" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_ft" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_lf" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_rt" ), true ),
				CResTextureData( _cfg.getString( "res_skybox_up" ), true )
			];

			CResTexture tmptex = sky.material.textures[$-1];

			tmptex.data[0].texType = ETexTarget.Tex_Cube_Z_Neg;
			tmptex.data[1].texType = ETexTarget.Tex_Cube_Y_Neg;
			tmptex.data[2].texType = ETexTarget.Tex_Cube_Z_Pos;
			tmptex.data[3].texType = ETexTarget.Tex_Cube_X_Pos;
			tmptex.data[4].texType = ETexTarget.Tex_Cube_X_Neg;
			tmptex.data[5].texType = ETexTarget.Tex_Cube_Y_Pos;

			tmptex.textureType = Tex_Cube;
			tmptex.swapCube = true;

//**************************************************************************************************

			auto light = new CEngLight( "someLight" );
			light.position.set( 0, 0, 0 );

			_cameras[0].position.set( 0.0, 4.5, 10.0 );
			_layers[0].addChild( light );

			auto pardust = new CEngParSystem( "anotherParSys" );
			pardust.position.set( 0,0,0 );
			pardust.xxTexture = _cfg.getString( "res_particle" );
			pardust.floats["maxsize"]	= 0.2f;
			pardust.floats["minsize"]	= 0.1f;
			pardust.floats["spread"]	= 0.0f;
			pardust.floats["posspread"]	= 100.0f;

			pardust.floats["rate"]		= 1000f;
			pardust.bools["lifedown"]	= false;
			pardust.ints["maxpar"]		= 1000;
			pardust.floats["maxspeed"]	= 0.0001f;
			pardust.floats["minspeed"]	= 0.0001f;

			pardust.bools["killdist"]	= true;
			pardust.floats["killdist"]  = 100.0f;

			pardust.vector.set(0,0,0);
			pardust.setCamera( _cameras[0] );
			pardust.rendType =  eparsysrendertype.sprites_rot;
			pardust.aligned =  eparsystalign.to_Camera;
			pardust.sort_Life = false;

			auto parAnim22 = new CSimplParAnimator( pardust );
			pardust.animators[ parAnim22.id ] = parAnim22;

			_cameras[0].addChild( pardust );
			_cameras[0].addChild( sky );

			debug debugLog.trace( "Demo scene: camera & layer are created" );

			// load config, create SFMASettings and create a free move animator,
			auto confFile = CMoonFile.drivers["program"].file( "camera.cfg" );
			auto freeMoveAnimatorConfig = new CConfig;

			if( confFile.exists )
			{
				auto stream = confFile.input;
				freeMoveAnimatorConfig.load( stream );
			}

			_freeCameraAnimator = new CFreeMoveAnimator( _cameras[0], SFMASettings( freeMoveAnimatorConfig ));
			_freeCameraAnimator.inverted = true;
			_cameras[0].animators[ "freemoveAnimator" ] = _freeCameraAnimator;
			_freeCameraAnimator.registerListener( CEngineCore(), eeventtype.program );

			debug debugLogB( "Demo scene initialization ended" );

			_initialized = true;

			debug CEngineCore().DbgReport;
			return true;
		}

		//================================================================
		/// process once
		//================================================================
		void run( float frametime )
		{
			// all processing stuff for objects in scene tree using frametime, including moves by accels from onEventCallback;
			foreach( layer; _layers )
				layer.update( frametime, _zeroVec, _idenMatrix );		// recursive processing
		}

		//================================================================
		/// event callback: all useful input from controllers, system and application comes here between scene runs
		//================================================================
		void onEventCallback( CEvent event, IEventGenerator gen )
		{
			// move camera (and other objects that receive event input,
			//  for example, from GUI elements, that generate gui events)
			passEvent( event, gen );
		}

		void onEventReceive( CEvent event, IEventSender sender )
		{
			//
		}

		//================================================================
		/// shutdown, release & clean stuff
		//================================================================
		void shutdown()
		{
			if( !_initialized || _shutdowndone )
				return;

			debug debugLogB( "customscene shutdown" );

			foreach( inout lr; _layers )
			{
				if( lr )
					delete lr;
			}

			_layers.length = 0;
			_cameras.length = 0;

			_shutdowndone = true;
			_initialized = false;
		}

		CConfig	getConfig()		{ return _cfg; }

		void	loadConfig()
		{
			if( _cfgFileName.length )
			{
				_cfg = null;
				_cfg = new CConfig( _cfgFileName );
			}
		}

		this( char[] cfgFileName = "demoscene.cfg" )
		{
			_id = "DemoScene";
			_zeroVec = Vector3f.zero;
			_idenMatrix = Matrix33f.identity;
			_cfgFileName = cfgFileName;
		}

		~this() { shutdown(); }
}
